//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package project_draw_api_serv

import (
	"context"
	"time"

	"atomgit.com/openlinksaas-org/api-server/api_common"
	"atomgit.com/openlinksaas-org/api-server/dao"
	"atomgit.com/openlinksaas-org/api-server/dao/project_draw_dao"
	"atomgit.com/openlinksaas-org/api-server/dao/project_entry_dao"
	"atomgit.com/openlinksaas-org/api-server/utils"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/project_draw_api"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/project_entry_api"
	"github.com/google/uuid"
	"go.mongodb.org/mongo-driver/mongo"
)

func (apiImpl *ProjectDrawApiImpl) CreateDraw(ctx context.Context, req *project_draw_api.CreateDrawRequest) (*project_draw_api.CreateDrawResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_draw_api.CreateDrawResponse{
			Code:   project_draw_api.CreateDrawResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	//检查权限
	projectItem, _, _, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_draw_api.CreateDrawResponse{
			Code:   project_draw_api.CreateDrawResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_draw_api.CreateDrawResponse{
			Code:   project_draw_api.CreateDrawResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_draw_api.CreateDrawResponse{
			Code:   project_draw_api.CreateDrawResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	drawId := uuid.NewString()

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = project_draw_dao.ContentDao.Insert(sessCtx, &project_draw_dao.ContentDbItem{
			DrawId:  drawId,
			Content: "",
		})
		if err != nil {
			return nil, err
		}
		return &project_draw_api.CreateDrawResponse{
			Code:   project_draw_api.CreateDrawResponse_CODE_OK,
			DrawId: drawId,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	return ret.(*project_draw_api.CreateDrawResponse), nil
}

func (apiImpl *ProjectDrawApiImpl) StartUpdateDraw(ctx context.Context, req *project_draw_api.StartUpdateDrawRequest) (*project_draw_api.StartUpdateDrawResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_draw_api.StartUpdateDrawResponse{
			Code:   project_draw_api.StartUpdateDrawResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	//检查权限
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_draw_api.StartUpdateDrawResponse{
			Code:   project_draw_api.StartUpdateDrawResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_draw_api.StartUpdateDrawResponse{
			Code:   project_draw_api.StartUpdateDrawResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}

	entryItem, err := project_entry_dao.EntryDao.Get(ctx, req.DrawId, req.ProjectId)
	if err != nil {
		return &project_draw_api.StartUpdateDrawResponse{
			Code:   project_draw_api.StartUpdateDrawResponse_CODE_NO_DRAW,
			ErrMsg: "绘图白板不存在",
		}, nil
	}
	if entryItem.EntryType != uint32(project_entry_api.ENTRY_TYPE_ENTRY_TYPE_DRAW) {
		return &project_draw_api.StartUpdateDrawResponse{
			Code:   project_draw_api.StartUpdateDrawResponse_CODE_NO_DRAW,
			ErrMsg: "绘图白板不存在",
		}, nil
	}

	canUpdate := api_common.CheckEntryCanUpdate(sessionItem, projectItem, roleItem, entryItem)

	if !canUpdate {
		return &project_draw_api.StartUpdateDrawResponse{
			Code:   project_draw_api.StartUpdateDrawResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	//检查是否有其他人在编辑

	editInfo, ok := dao.CacheDao.GetEntryEdit(ctx, req.DrawId)
	if ok {
		if editInfo.ProjectId != req.ProjectId || editInfo.EditUserId != sessionItem.UserId {
			return &project_draw_api.StartUpdateDrawResponse{
				Code:   project_draw_api.StartUpdateDrawResponse_CODE_NO_PERMISSION, //FIXME
				ErrMsg: "没有权限",
			}, nil
		}
	}

	//创建cache对象
	err = dao.CacheDao.SetEntryEdit(ctx, &dao.EntryEditDbItem{
		ProjectId:  req.ProjectId,
		EntryId:    req.DrawId,
		EditUserId: sessionItem.UserId,
	})
	if err != nil {
		return nil, err
	}
	return &project_draw_api.StartUpdateDrawResponse{
		Code: project_draw_api.StartUpdateDrawResponse_CODE_OK,
	}, nil
}

func (apiImpl *ProjectDrawApiImpl) KeepUpdateDraw(ctx context.Context, req *project_draw_api.KeepUpdateDrawRequest) (*project_draw_api.KeepUpdateDrawResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_draw_api.KeepUpdateDrawResponse{
			Code:       project_draw_api.KeepUpdateDrawResponse_CODE_WRONG_SESSION,
			ErrMsg:     "会话不存在",
			KeepUpdate: false,
		}, nil
	}
	editInfo, ok := dao.CacheDao.GetEntryEdit(ctx, req.DrawId)
	if !ok {
		return &project_draw_api.KeepUpdateDrawResponse{
			Code:       project_draw_api.KeepUpdateDrawResponse_CODE_NO_PERMISSION,
			ErrMsg:     "没有权限",
			KeepUpdate: false,
		}, nil
	}
	if editInfo.EditUserId != sessionItem.UserId {
		return &project_draw_api.KeepUpdateDrawResponse{
			Code:       project_draw_api.KeepUpdateDrawResponse_CODE_NO_PERMISSION,
			ErrMsg:     "没有权限",
			KeepUpdate: false,
		}, nil
	}
	dao.CacheDao.KeepEntryEdit(ctx, req.DrawId)
	return &project_draw_api.KeepUpdateDrawResponse{
		Code:       project_draw_api.KeepUpdateDrawResponse_CODE_OK,
		KeepUpdate: true,
	}, nil
}

func (apiImpl *ProjectDrawApiImpl) EndUpdateDraw(ctx context.Context, req *project_draw_api.EndUpdateDrawRequest) (*project_draw_api.EndUpdateDrawResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_draw_api.EndUpdateDrawResponse{
			Code:   project_draw_api.EndUpdateDrawResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	editInfo, ok := dao.CacheDao.GetEntryEdit(ctx, req.DrawId)
	if !ok {
		return &project_draw_api.EndUpdateDrawResponse{
			Code: project_draw_api.EndUpdateDrawResponse_CODE_OK,
		}, nil
	}

	if editInfo.EditUserId != sessionItem.UserId {
		return &project_draw_api.EndUpdateDrawResponse{
			Code:   project_draw_api.EndUpdateDrawResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	dao.CacheDao.RemoveEntryEdit(ctx, req.DrawId)
	return &project_draw_api.EndUpdateDrawResponse{
		Code: project_draw_api.EndUpdateDrawResponse_CODE_OK,
	}, nil
}

func (apiImpl *ProjectDrawApiImpl) UpdateDraw(ctx context.Context, req *project_draw_api.UpdateDrawRequest) (*project_draw_api.UpdateDrawResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_draw_api.UpdateDrawResponse{
			Code:   project_draw_api.UpdateDrawResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	//检查权限
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_draw_api.UpdateDrawResponse{
			Code:   project_draw_api.UpdateDrawResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_draw_api.UpdateDrawResponse{
			Code:   project_draw_api.UpdateDrawResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_draw_api.UpdateDrawResponse{
			Code:   project_draw_api.UpdateDrawResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	entryItem, err := project_entry_dao.EntryDao.Get(ctx, req.DrawId, req.ProjectId)
	if err != nil {
		return &project_draw_api.UpdateDrawResponse{
			Code:   project_draw_api.UpdateDrawResponse_CODE_NO_DRAW,
			ErrMsg: "绘图白板不存在",
		}, nil
	}
	if entryItem.EntryType != uint32(project_entry_api.ENTRY_TYPE_ENTRY_TYPE_DRAW) {
		return &project_draw_api.UpdateDrawResponse{
			Code:   project_draw_api.UpdateDrawResponse_CODE_NO_DRAW,
			ErrMsg: "绘图白板不存在",
		}, nil
	}

	hasUpdatePerm := api_common.CheckEntryCanUpdate(sessionItem, projectItem, roleItem, entryItem)

	if !hasUpdatePerm {
		return &project_draw_api.UpdateDrawResponse{
			Code:   project_draw_api.UpdateDrawResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	//检查编辑状态
	editInfo, ok := dao.CacheDao.GetEntryEdit(ctx, req.DrawId)
	if !ok {
		return &project_draw_api.UpdateDrawResponse{
			Code:   project_draw_api.UpdateDrawResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	if editInfo.ProjectId != req.ProjectId || editInfo.EntryId != req.DrawId || editInfo.EditUserId != sessionItem.UserId {
		return &project_draw_api.UpdateDrawResponse{
			Code:   project_draw_api.UpdateDrawResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	contentItem, err := project_draw_dao.ContentDao.Get(ctx, req.DrawId)
	if err != nil {
		return nil, err
	}
	//不保存重复内容
	if req.Content == contentItem.Content {
		dao.CacheDao.RemoveEntryEdit(ctx, req.DrawId)
		return &project_draw_api.UpdateDrawResponse{
			Code: project_draw_api.UpdateDrawResponse_CODE_OK,
		}, nil
	}

	nowTime := time.Now().UnixNano() / 1e6
	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = project_draw_dao.ContentDao.Update(sessCtx, req.DrawId, req.Content)
		if err != nil {
			return nil, err
		}
		err = project_entry_dao.EntryDao.SetUpdateInfo(sessCtx, req.DrawId, req.ProjectId, sessionItem.UserId, nowTime)
		if err != nil {
			return nil, err
		}
		return &project_draw_api.UpdateDrawResponse{
			Code: project_draw_api.UpdateDrawResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}

	return ret.(*project_draw_api.UpdateDrawResponse), nil
}

func (apiImpl *ProjectDrawApiImpl) GetDraw(ctx context.Context, req *project_draw_api.GetDrawRequest) (*project_draw_api.GetDrawResponse, error) {
	emptyInfo := &project_draw_api.DrawInfo{}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_draw_api.GetDrawResponse{
			Code:   project_draw_api.GetDrawResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
			Info:   emptyInfo,
		}, nil
	}
	//检查权限
	_, _, _, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_draw_api.GetDrawResponse{
			Code:   project_draw_api.GetDrawResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
			Info:   emptyInfo,
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_draw_api.GetDrawResponse{
			Code:   project_draw_api.GetDrawResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
			Info:   emptyInfo,
		}, nil
	} else if err != nil {
		return nil, err
	}

	contentItem, err := project_draw_dao.ContentDao.Get(ctx, req.DrawId)
	if err != nil {
		return &project_draw_api.GetDrawResponse{
			Code:   project_draw_api.GetDrawResponse_CODE_NO_DRAW,
			ErrMsg: "绘图白板不存在",
			Info:   emptyInfo,
		}, nil
	}

	return &project_draw_api.GetDrawResponse{
		Code: project_draw_api.GetDrawResponse_CODE_OK,
		Info: &project_draw_api.DrawInfo{
			DrawId:  req.DrawId,
			Content: contentItem.Content,
		},
	}, nil
}
